﻿using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;
using System.Drawing;
//
//====================================================================================================================================================================
// Add User Rating Web Part to Blog Site for SharePoint 2010
// Provided as an example best practice - David M. Sterling - david_sterling@sterling-consulting.com
// Sterling International Consulting Group - www.sterling-consulting.com - Architects, Designers, Instructors
// Use at your own risk!
//
// This part is a way to provide on-page rating for Blog Posts using the User Rating Web Part (userratingwebpart.codeplex.com). This is an example of using a web 
// part to overcome an issue in the SharePoint User Interface (you can turn on ratings but they require navigation to the list to set).
//====================================================================================================================================================================
//
namespace AddRatingsToBlogSites.AddRatingsToBlogWP
{
    [ToolboxItemAttribute(false)]
    public class AddRatingsToBlogWP : System.Web.UI.WebControls.WebParts.WebPart
    {
        //
        #region Global Variables
        //
        protected bool ContinueProcessing = true;
        protected string WhatWasError = "";
        //
        #endregion
        //
        #region Controls
        //
        TextBox TheBlogSiteURLPath = new TextBox();
        Label ErrorMessageIfAny = new Label();
        System.Web.UI.WebControls.Image TheDisplayHeaderImage = new System.Web.UI.WebControls.Image();
        Button UpdateSite = new Button();
        //
        #endregion
        //
        #region Override Methods
        //
        //============================================================================================================================================================
        /// <summary>
        /// OnLoad Event
        /// </summary>
        //============================================================================================================================================================
        /// <param name="e"></param>
        /// 
        protected override void OnLoad(EventArgs e)
        {
            TheDisplayHeaderImage.ID = "TheDisplayHeaderImage";
            TheDisplayHeaderImage.ImageAlign = ImageAlign.AbsMiddle;
            TheDisplayHeaderImage.ImageUrl = "/_layouts/images/ratingsnew.png";
            this.Controls.Add(TheDisplayHeaderImage);

            TheBlogSiteURLPath.ID = "TheBlogSiteURLPath";
            TheBlogSiteURLPath.Font.Name = "Verdana";
            TheBlogSiteURLPath.Font.Size = System.Web.UI.WebControls.FontUnit.Point(10);
            TheBlogSiteURLPath.Width = System.Web.UI.WebControls.Unit.Pixel(175);
            TheBlogSiteURLPath.CssClass = "ms-descriptiontext";
            this.Controls.Add(TheBlogSiteURLPath);

            UpdateSite.ID = "UpdateSite";
            UpdateSite.Text = "Update Site";
            UpdateSite.Font.Name = "Verdana";
            UpdateSite.Font.Size = System.Web.UI.WebControls.FontUnit.Point(10);
            UpdateSite.Font.Bold = true;
            UpdateSite.Click += new EventHandler(UpdateSite_Click);
            this.Controls.Add(UpdateSite);

            ErrorMessageIfAny.ID = "ErrorMessageIfAny";
            ErrorMessageIfAny.Font.Name = "Verdana";
            ErrorMessageIfAny.Font.Size = System.Web.UI.WebControls.FontUnit.Point(10);
            ErrorMessageIfAny.ForeColor = System.Drawing.Color.Red;
            ErrorMessageIfAny.CssClass = "ms-descriptiontext";
            ErrorMessageIfAny.Width = System.Web.UI.WebControls.Unit.Pixel(220);
            this.Controls.Add(ErrorMessageIfAny);
        }
        //
        //============================================================================================================================================================
        /// <summary>
        /// UpdateSite_Click - Update the selected site
        /// </summary>
        //============================================================================================================================================================
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 
        void UpdateSite_Click(object sender, EventArgs e)
        {
            //
            ErrorMessageIfAny.ForeColor = System.Drawing.Color.Red;
            if (String.IsNullOrEmpty(TheBlogSiteURLPath.Text))
            {
                ErrorMessageIfAny.Text = "Must specify a URL";
                TheBlogSiteURLPath.Focus();
                return;
            }
            if (TheBlogSiteURLPath.Text.ToLower().IndexOf("http:") == -1)
            {
                ErrorMessageIfAny.Text = "Must specify a Full URL (http included)";
                TheBlogSiteURLPath.Focus();
                return;
            }
            ErrorMessageIfAny.Text = "";
            //
            string ValOf = TheBlogSiteURLPath.Text;
            //
            EnableBlogSiteRatings(ValOf);
            //
            // Did we make it?
            //
            if (!ContinueProcessing)
            {
                // Deal with the error
                ErrorMessageIfAny.Text = WhatWasError;
            }
            else
            {
                // All is well!
                ErrorMessageIfAny.ForeColor = System.Drawing.Color.Green;
                ErrorMessageIfAny.Text = "Update to the site at " + TheBlogSiteURLPath.Text + " was successful!";
                TheBlogSiteURLPath.Text = "";
            }            
        }
        //
        //============================================================================================================================================================
        /// <summary>
        /// Render Event
        /// </summary>
        //============================================================================================================================================================
        /// <param name="writer"></param>
        /// 
        protected override void Render(HtmlTextWriter writer)
        {
            writer.Write("<style type=\"text/css\">");
            writer.Write("#containerBox {width:300px; margin:auto;}");
            writer.Write("#contentBox, .shadowBox { position: relative;bottom: 4px;right: 4px; -moz-border-radius:15px;border-radius: 15px; }");
            writer.Write("#shadowBox { background-color: #ccc; }");
            writer.Write("#contentBox { vertical-align:top;background-color: #fff;color: #000;border: 1px solid #ccc;padding: 0.5em;font-family: Verdana, Arial;}");
            writer.Write("</style>");
 
            writer.Write("<div id=\"containerBox\">");
            writer.Write("   <div id=\"shadowBox\">");
            writer.Write("     <div id=\"contentBox\">");
            writer.Write("<h3 style=\"padding-left:4px;\">");
            TheDisplayHeaderImage.RenderControl(writer);
            writer.Write("&nbsp;Add Rating to Blog Site");
            writer.Write("</h3>");
            writer.Write("<p class=\"ms-descriptiontext\" style=\"text-align:center;\" >This utility enables adding of the ratings feature to the specified blog site.");
            writer.Write("<br /><br />");
            writer.Write("<i>This utility can only be run once per site and does not remove (removing must be done manually or by dropping & recreating the site).</i>");
            writer.Write("<br /><br />");
            writer.Write("Enter the full URL to the blog site<br />(i.e http://site/site):");
            writer.Write("<br />");
            TheBlogSiteURLPath.RenderControl(writer);
            writer.Write("<br /><br />");
            UpdateSite.RenderControl(writer);
            writer.Write("<br /><br />");
            ErrorMessageIfAny.RenderControl(writer);
            writer.Write("</p>");
            writer.Write("     </div>");
            writer.Write("   </div>");
            writer.Write(" </div>");


        }
        //
        #endregion
        //
        #region Custom Methods
        //
        //============================================================================================================================================================
        /// <summary>
        /// EnableBlogSiteRatings - Enable the blog site ratings
        /// </summary>
        //============================================================================================================================================================
        /// <param name="TheBlogSite">The URL to the Blog Site to add ratings to (full url as in http://<site>/<site>)</param>
        //
        public void EnableBlogSiteRatings(string TheBlogSiteURL)
        {
            //
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite TheBlogSite = new SPSite(TheBlogSiteURL))
                    {
                        using (SPWeb TheWebRef = TheBlogSite.OpenWeb())
                        {
                            TheWebRef.AllowUnsafeUpdates = true;
                            //
                            // Check type:
                            //
                            if (TheWebRef.WebTemplate != SPWebTemplate.WebTemplateBLOG)
                            {
                                ContinueProcessing = false;
                                WhatWasError = "Error - the web site at " + TheBlogSiteURL + " is not a blog site";
                                return;
                            }
                            //
                            SPFileCollection SPFC = null;
                            SPList PostsList = TheWebRef.Lists["Posts"];
                            //
                            // Once we have the Post list, we check to see if we have to enable ratings:
                            //
                            bool FieldsFound = CheckForRatingsField(PostsList);
                            //
                            if (!FieldsFound)
                            {
                                string RtnMessage = AddRatingsFieldsToList(PostsList);
                                if (!String.IsNullOrEmpty(RtnMessage))
                                {
                                    if (RtnMessage.ToLower().IndexOf("duplicate") > -1)
                                    {
                                        // Fields already there - keep trying:
                                        ContinueProcessing = true;
                                    }
                                    else
                                    {
                                        ContinueProcessing = false;
                                        WhatWasError = RtnMessage;
                                    }
                                }
                            }
                            //
                            // Continue if we can:
                            //
                            if (ContinueProcessing)
                            {
                                //
                                // Get the collection of root folder files (these are the files 'behind' the list):
                                //
                                try
                                {
                                    SPFC = PostsList.RootFolder.Files;
                                    if (SPFC.Count < 1)
                                    {
                                        ContinueProcessing = false;
                                        WhatWasError = "Error - unable trying to access Post List Root Folder; returned Zero files?";
                                    }
                                }
                                catch (Exception ErrIn)
                                {
                                    string WhyErr = ErrIn.Message.ToString();
                                    ContinueProcessing = false;
                                    WhatWasError = "Error - unable trying to access Post List Root Folder - message: " + WhyErr;
                                }
                                //
                                if (ContinueProcessing)
                                {
                                    foreach (SPFile AFile in SPFC)
                                    {
                                        if (AFile.Name == "Post.aspx")
                                        {
                                            //
                                            // Add our web part to the page - any problem will be reported in WhatWasError:
                                            //
                                            string RtndID = AddWebPartToPage(TheWebRef, AFile.Url, "UserRatingWP.webpart", "Left", 2);
                                            //
                                            break;
                                        }
                                    }
                                }
                            }
                            TheWebRef.AllowUnsafeUpdates = false;

                        }
                    }
                });
            }
            catch (Exception ErrIn)
            {
                string WhyErr = ErrIn.Message.ToString();
                ContinueProcessing = false;
                if (WhyErr.IndexOf("not be found") > -1)
                {
                    WhatWasError = "Error - the web site at " + TheBlogSiteURL + " was not found, check URL and try again";
                }
                else
                {
                    WhatWasError = "Error - unexpected error accessing web site at " + TheBlogSiteURL + ", error : " + WhyErr;
                }
            }
        }
        //
        //============================================================================================================================================================
        /// <summary>
        /// CheckForRatingsField - Check a list/library to see if the rating field exists (found means turned on already)
        /// </summary>
        //============================================================================================================================================================
        /// <param name="list">The list check for the Ratings field (SPList)</param>
        /// <returns>True or False if the field exists (bool)</returns>
        /// 
        public bool CheckForRatingsField(SPList List)
        {
            bool FieldsFound = false;
            //
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb TheWeb = List.ParentWeb)
                {
                    TheWeb.AllowUnsafeUpdates = true;
                    if (List.Fields.ContainsFieldWithStaticName("AverageRating"))
                    {
                        FieldsFound = true;
                    }
                    else if (List.Fields.Contains(new System.Guid("5a14d1ab-1513-48c7-97b3-657a5ba6c742")))
                    {
                        FieldsFound = true;
                    }
                    TheWeb.AllowUnsafeUpdates = false;
                }
            });
            return FieldsFound;
        }
        //
        //============================================================================================================================================================
        /// <summary>
        /// AddRatingsFieldsToList - Adds the ratings fields to the List/Library passed (if needed)
        /// </summary>
        //============================================================================================================================================================
        /// <param name="list">The list to add the fields to (SPList)</param>
        /// <returns>Status message (string)</eturns>
        /// 
        public string AddRatingsFieldsToList(SPList list)
        {
            // If OK, we return nothing:
            //
            string MessageToReturn = "";
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb ParentWeb = list.ParentWeb)
                {
                    ParentWeb.AllowUnsafeUpdates = true;
                    ParentWeb.ValidateFormDigest();
                    try
                    {
                        //Add the average rating field.
                        SPField averageRatingField = list.ParentWeb.AvailableFields[new Guid("5a14d1ab-1513-48c7-97b3-657a5ba6c742")];
                        list.Fields.AddFieldAsXml(averageRatingField.SchemaXml, true, SPAddFieldOptions.AddToAllContentTypes | SPAddFieldOptions.AddFieldToDefaultView);

                        //Add the rating count field.
                        SPField ratingCountField = list.ParentWeb.AvailableFields[new Guid("b1996002-9167-45e5-a4df-b2c41c6723c7")];
                        list.Fields.AddFieldAsXml(ratingCountField.SchemaXml, true, SPAddFieldOptions.AddToAllContentTypes | SPAddFieldOptions.AddFieldToDefaultView);
                    }
                    catch (Exception ErrIn)
                    {
                        string WhyErr = ErrIn.Message.ToString();
                        MessageToReturn = "Error - unable to add Ratings Fields to the Posts List - message: " + WhyErr;
                    }
                    ParentWeb.AllowUnsafeUpdates = false;
                }
            });
            return MessageToReturn;
        }
        //
        // Convert string to bytes:
        //
        public static byte[] StrToByteArray(string str)
        {
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            return encoding.GetBytes(str);
        }
        //
        // Convert bytes to string:
        //
        public static string ByteArrayToString(byte[] BytesArray)
        {
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            return encoding.GetString(BytesArray);
        }
        //
        //============================================================================================================================================================
        /// <summary>
        /// CreateWebPart - Create the web part to add to the page
        /// </summary>
        //============================================================================================================================================================
        /// <param name="web">The current web site (SPWeb)</param>
        /// <param name="webPartName">Name of the .webpart filename (string)</param>
        /// <returns>The web part created (System.Web.UI.WebControls.WebParts.WebPart)</returns>
        /// 
        private System.Web.UI.WebControls.WebParts.WebPart CreateWebPart(SPWeb web, string webPartName)
        {
            //
            // Create the web part so we can add it to the page - first, setup the query to find the web part in the web
            // part gallery (note that the actual File Name is used (i.e. the .webpart file name as is part.webpart):
            //
            SPList webPartGallery = null;
            SPListItemCollection webParts = null;
            System.Web.UI.WebControls.WebParts.WebPart webPart = null;
            bool FoundByName = false;
            ContinueProcessing = false;
            string typeName = "UserRatingWebPart.UserRatingWP.UserRatingWP";
            string assemblyName = "UserRatingWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4343cfce06d81fe9";
            //
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                web.AllowUnsafeUpdates = true;
                //
                // Set the defaults - we try with this in the event we cannot find it:
                //
                try
                {
                    SPQuery query = new SPQuery();
                    query.Query = String.Format("<Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='File'>{0}</Value></Eq></Where>", webPartName);
                    //
                    // Wherever we may be, use the site to get to the root:
                    //
                    webPartGallery = web.Site.RootWeb.GetCatalog(SPListTemplateType.WebPartCatalog);
                    //
                    // Run the query to find it:
                    //
                    webParts = webPartGallery.GetItems(query);
                    //
                    // Make sure we got one:
                    //
                    if (webParts.Count > 0)
                    {
                        typeName = webParts[0].GetFormattedValue("WebPartTypeName");
                        assemblyName = webParts[0].GetFormattedValue("WebPartAssembly");
                        WhatWasError = "";
                        ContinueProcessing = true;
                    }
                    else
                    {
                        // DMS: Let it fall through even if it can't find it - we will trap the failure to create the
                        // web part itself...The above works in every enivornment except Production.
                        //
                        //ContinueProcessing = false;
                        //WhatWasError = "Error - Did not file the web part " + webPartName + " in the Web Part Gallery; check deployment";
                        //
                        // DMS Test: In some environments, the above is not working, try to find it manually:
                        //
                        foreach (SPListItem AnItem in webPartGallery.Items)
                        {
                            string TestLeafName = (string)AnItem["FileLeafRef"].ToString();
                            string TestTitle = (string)AnItem["Title"].ToString();
                            if (TestLeafName.IndexOf("UserRatingWP") > -1)
                            {
                                typeName = (string)AnItem.GetFormattedValue("WebPartTypeName");
                                assemblyName = (string)AnItem.GetFormattedValue("WebPartAssembly");
                                ContinueProcessing = true;
                                FoundByName = true;
                                WhatWasError = "";
                                break;
                            }
                            if (TestTitle.IndexOf("Rating Web Part") > -1)
                            {
                                typeName = (string)AnItem.GetFormattedValue("WebPartTypeName");
                                assemblyName = (string)AnItem.GetFormattedValue("WebPartAssembly");
                                ContinueProcessing = true;
                                FoundByName = true;
                                WhatWasError = "";
                                break;
                            }
                        }
                    }
                }
                catch (Exception ErrIn)
                {
                    ContinueProcessing = false;
                    WhatWasError = "Error - Error trying to access the Web Part Gallery in the Root Web - Check permissions/deployment - message; " + ErrIn.Message.ToString();
                }
                //
                // Create the web part if we found it:
                // 
                //ContinueProcessing = false;
                //WhatWasError = "Error - Did not file the web part " + webPartName + " in the Web Part Gallery; check deployment";
                //
                // Try it anyway:
                //
                if (!ContinueProcessing)
                {
                    ContinueProcessing = true;
                    try
                    {
                        // Use defaults:
                        //
                        typeName = "UserRatingWebPart.UserRatingWP.UserRatingWP";
                        assemblyName = "UserRatingWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4343cfce06d81fe9";
                        System.Runtime.Remoting.ObjectHandle webPartHandle = Activator.CreateInstance(assemblyName, typeName);
                        webPart = (System.Web.UI.WebControls.WebParts.WebPart)webPartHandle.Unwrap();
                        webPart.Title = "Post Rating";
                        webPart.Description = "Adds Social Ratings to blog posts.";
                        webPart.ChromeType = PartChromeType.None;

                    }
                    catch (Exception ErrIn)
                    {
                        string WhyErr = ErrIn.Message.ToString();
                        ContinueProcessing = false;
                        if (WhyErr.IndexOf("Could not load file or assembly 'UserRatingWebPart") > -1)
                        {
                            WhatWasError = "Error - User Rating Web Part could not be accessed so it cannot be added to a blog site (cannot find in Gallery or by using default values)";
                        }
                        else
                        {
                            WhatWasError = "Error - Problem accesing the User Rating Web Part (cannot find in Gallery or by using default values) - error: " + WhyErr;
                        }
                    }
                }
                else // Continue already set
                {
                    try
                    {
                        System.Runtime.Remoting.ObjectHandle webPartHandle = Activator.CreateInstance(assemblyName, typeName);
                        webPart = (System.Web.UI.WebControls.WebParts.WebPart)webPartHandle.Unwrap();
                        webPart.Title = "Post Rating";
                        webPart.Description = "Adds Social Ratings to blog posts.";
                        webPart.ChromeType = PartChromeType.None;
                    }
                    catch (Exception ErrIn)
                    {
                        string WhyErr = ErrIn.Message.ToString();
                        ContinueProcessing = false;
                        if (WhyErr.IndexOf("Could not load file or assembly 'UserRatingWebPart") > -1)
                        {
                            WhatWasError = "Error - User Rating Web Part is not installed so it cannot be added to a blog site - install this part and retry this process";
                        }
                        else
                        {
                            WhatWasError = "Error - Problem accesing the User Rating Web Part - error: " + WhyErr;
                        }
                    }
                }
                web.AllowUnsafeUpdates = false;
            });
            //
            // Return what we got (a WebPart or null):
            //
            return webPart;
        }
        //
        //============================================================================================================================================================
        /// <summary>
        /// AddWebPartToPage - Add a web part to a specific page in the site
        /// </summary>
        //============================================================================================================================================================
        /// <param name="web">The current web site (SPWeb)</param>
        /// <param name="pageUrl">The full Url to the page to add the web part to (string)</param>
        /// <param name="webPartName">Name of the .webpart filename (string)</param>
        /// <param name="zoneID">The Web Part Zone ID on the page to add the part to (i.e. Left) (string)</param>
        /// <param name="zoneIndex">The number (order) of the part within the zone (i.e. 1, 2) (int)</param>
        /// <returns></returns>
        /// 
        public string AddWebPartToPage(SPWeb web, string pageUrl, string webPartName, string zoneID, int zoneIndex)
        {
            //
            string WebPartID = "";
            //
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (System.Web.UI.WebControls.WebParts.WebPart webPart = CreateWebPart(web, webPartName))
                {
                    web.AllowUnsafeUpdates = true;
                    if (webPart != null)
                    {
                        using (SPLimitedWebPartManager manager = web.GetLimitedWebPartManager(pageUrl, PersonalizationScope.Shared))
                        {
                            //
                            // Scope it out to make sure the part is NOT already there:
                            //
                            foreach (System.Web.UI.WebControls.WebParts.WebPart AWP in manager.WebParts)
                            {
                                string AWPTitle = AWP.Title;
                                if (AWPTitle == "Post Rating")
                                {
                                    ContinueProcessing = false;
                                    WhatWasError = "Error - web part already on the page; if not showing, check publishing status";
                                    break;
                                }
                            }
                            //
                            if (ContinueProcessing)
                            {
                                try
                                {
                                    manager.AddWebPart(webPart, zoneID, zoneIndex);
                                    ////
                                    //// Go find it so we can set the chrome:
                                    ////
                                    //foreach (System.Web.UI.WebControls.WebParts.WebPart AWP in manager.WebParts)
                                    //{
                                    //    string AWPTitle = AWP.Title;
                                    //    if (AWPTitle == "Post Rating")
                                    //    {
                                    //        AWP.ChromeType = PartChromeType.None;
                                    //        break;
                                    //    }
                                    //}
                                }
                                catch (Exception ErrInAdd)
                                {
                                    ContinueProcessing = false;
                                    WhatWasError = "Error - unable to add the web part to the page, check permissions/access - message: " + ErrInAdd.Message.ToString();
                                    WebPartID = "Error";
                                }
                            }
                            WebPartID = webPart.ID;
                        }
                    }
                    else
                    {
                        WebPartID = "Error";
                    }
                    web.AllowUnsafeUpdates = false;
                }
            });
            //
            return WebPartID;
            //
        }
        //
        #endregion
        //
        //============================================================================================================================================================
        // End of class
        //============================================================================================================================================================
        //

        //// Visual Studio might automatically update this path when you change the Visual Web Part project item.
        //private const string _ascxPath = @"~/_CONTROLTEMPLATES/AddRatingsToBlogSites/AddRatingsToBlogWP/AddRatingsToBlogWPUserControl.ascx";

        //protected override void CreateChildControls()
        //{
        //    Control control = Page.LoadControl(_ascxPath);
        //    Controls.Add(control);
        //}
    }
}
